package vnc.server.rfb.messages;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;

import vnc.server.rfb.JavaInStream;
import vnc.server.rfb.JavaOutStream;

/**
 * REFACTOR ME!!
 *
 */
public abstract class Message {
	
	protected Socket clientSocket;
	
	protected OutputStream out;
	protected InputStream in;
	protected DataInputStream din;
	/**
	 * @deprecated
	 */
	protected DataOutputStream dout;
	protected BufferedReader bin;
	protected BufferedWriter bout;
	protected JavaOutStream jout;
	protected JavaInStream jin;

	protected final BufferedOutputStream bufferedOutputStream;
	protected final ProcessMode processMode;
	enum ProcessMode{
		read,
		write,
		readAndWrite
	}
	
	public Message(Socket clientSocket, ProcessMode mode)
	{
		this.processMode = mode;
		this.clientSocket = clientSocket;
		try {
			out = clientSocket.getOutputStream();
			in = clientSocket.getInputStream();
			din = new DataInputStream(in);
			dout = new DataOutputStream(out);
			bin = new BufferedReader(new InputStreamReader(in));
			bout = new BufferedWriter(new OutputStreamWriter(out));
			bufferedOutputStream = new BufferedOutputStream( out, 5*1024*1024);
			jout = new JavaOutStream(bufferedOutputStream);
			jin = new JavaInStream(in);
		}
		catch(Exception e) {
			throw new IllegalStateException("Unable to init streams");
		}
		
		
	}
	/**
	 * Should be implemented by clients.
	 * @throws IOException
	 */
	protected Object doReadMessage() throws IOException { return null;}
	
	protected void doWriteMessage(Object readData) throws IOException {}
	
	/**
	 * TODO: make synchronization on object common to all Message processors( Might be a socket ).
	 * @throws IOException
	 */
	public void process() throws IOException{
		switch (processMode) {
		case read:
			synchronized (jin) {
				doReadMessage();
			}
			break;

		case write:
			synchronized (jout) {
				doWriteMessage(null);
			}
			break;
		case readAndWrite:
			Object readData;
			synchronized (jin) {
				readData = doReadMessage();
			}
			synchronized (jout) {
				doWriteMessage(readData);
			}
			break;
		}
		
	};
	
}
